package Day6;

import org.junit.Test;

import java.util.*;

/**
 * @author ：Yan Guang
 * @date ：Created in 2020/5/2 6:29
 * @description：/----Map:双列数据，存储key-value对的数据 ---类似于高中的函数: y = f(x)
 * /----HashMap:作为Map的主要实现类，主要用这个，效率高：可以存储null的key跟values
 * /----LinkedHashMap:添加的时候可以按照添加的顺序来实现遍历，因为添加了指针，对于频繁的遍历，适合使用
 * .  / ---- TreeMap:可以按照key-value来进行排序，但是是进行key来排序
 * 底层使用的是红黑树
 * /----Hashtable:作为古老的实现类，不怎么用，线程安全，效率低
 * /----Properties:常用来处理配置文件，key和value都是tring类型
 * <p>
 * HashMap的底层:数组+链表(jdk7及之前)
 * 数组+链表+红黑树(jdk 8)
 * <p>
 * 面试题:
 * 1. HashMap的底层实现原理?
 * 2.HashMap和Hashtable的异同?
 * <p>
 * 二、Map结构的理解:
 * Map中的key:无序的、不可重复的，使用Set 存储所有的key----->key的类要重写eqluas跟hashcode函数
 * Map中的value:无序的、可重复的，使用Collection存 储所有的value------->value所在类要重写equlas（）；
 * 一个 键值对: key-value构成 了一个Entry对象 。
 * Map中的entry:无序的、不可重复的，使用Set 存储所有的entry
 * <p>
 * 三、HashMap的底层实现原理?    以jdk7为例说明:
 * HashMap map = new HashMap():
 * 在实例化以后，底层创建了长度是16的一-维数组Entry[] table.
 * ...可能已经执行过多次put...
 * map. put (key1, value1):
 * 首先，调用key1所在类的hashCode() 计算key1哈希值，此哈希值经过某种算法计算以后，得到在Entry 数组中的存放位置。
 * 如果此位置上的数据为空，此时key1-value1 添加成功
 * 如果此位置上的数据不为空（意味着已经存在了数据（以链表形式存在）），我们需要比较key的hash值：
 * 如果key1的哈希值与已经存在的数据的哈希值都不相同，此时key1 -value1添加成功。-------情况2
 * 如果key1的哈希值和已经存在的某一个数据(key2-value2)的哈希值相同，继续比较:调用key1 所在类的equals（key2）
 * 如果equals()返回false:此时key1-value1添加成功。---------------情况3
 * 如果equals()返回true:使用value1替换value2。
 * <p>
 * 补充:关于情况2和情况3:此时key1-value1 和原来的数据以链表的方式存储。
 * <p>
 * 在不断的添加过程中，会涉及到扩容问题，当超出临界值（且存放的的位置非空）默认的扩容方式:扩容为原来容量的2倍，并将原有的数据复制过来。
 * <p>
 * jdk8相较Fjdk7在底层实现方面的不同:
 * 1. new HashMap(): 底层没有创建-一个长度为16的数组
 * 2. jdk 8底层的数组是: Node[], 而非Entry[]
 * 3.首次调用put()方法时，底层创建长度为16的数组
 * 4. jdk7底层结构只有:数组+链表。jdk8中底层结构:数组+链表+红黑树。.
 * 当数组的某一个索引位置 上的元素以链表形式存在的数据个数> 8且当前数组的长度> 64时,
 * 此时此索引位置上的所有数据改为使用红黑树存储。索引能更加快速高效
 * <p>
 * hashmap中
 * DEFAULT_ INITIAL_ CAPACITY : HashMap 的默认容量，16
 * DEFAULT_ LOAD_ FACTOR: HashMap 的默认加载因子: 0.75
 * *
 * threshold:扩容的临界值，=容量*填充因子: 16 * 0.75 => 12
 * TREEIFY_ THRESHOLD: Bucket 中链表长度大于该默认值，转化为红黑树:8
 * *
 * MIN_ TREEIFY_ CAPACITY: 桶中的Node被树化时最小的hash表容量:64
 * *四、 LinkedHashMap的底层实现原理(了解)
 * <p>
 * 源码中:
 * *
 * static class Entry<K, V> extends HashMap. Node<K, V>{
 * Entry<K,V> before, after;
 * Entry(int hash, K key, V value, Node<K,V> next) {
 * super(hash, key, value, next);
 * 能够记录添加元素的先后顺序，以此达到遍历，所以说linkdehashmap在很多遍历的时候使用
 * <p>
 * 五、Map接口中定义的方法:
 * |添加、删除、修改操作:
 * Object put(Object key, Object value): 将指定key-value 添加到(或修改)当前map对象中
 * void putALl(Map m): 将m中的所有key-value对存放到当前map中
 * object remove(Object key): 移除指定key的key-value对，并返回value
 * void clear(): 清空当前map中的所有数据
 * 元素查询的操作:
 * object get(object key): 获取指定key对应的value
 * boolean containsKey(ob[ject key): 是否包含指定的key
 * boolean containsValue(Object value): 是否包含指定的value
 * int size(): 返回map中key-value对的个数
 * boolean isEmpty(): 判断当前map是否为空
 * boolean equals(object obj): 判断当前map和参数对象obj是否相等
 * 元视图操作的方法:
 * Set keySet(): 返回所有key构成的Set集合
 * Collection values(): 返回所有value 构成的Collection集合
 * Set entrySet(): 返回所有key-value对构成的Set集合
 */
public class MapTest {
    @Test
    public void test1() {
        Map m1 = new HashMap();
        m1.put(null, null);//HashMap可以放null

    }

    @Test
    public void test2() {
        Map map = new LinkedHashMap();
        map.put(123, "cddsfd");
        map.put(22, "asjk");
        map.put(333, "bwqed");

        System.out.println(map);

    }

    //添加、删除、修改操作:
    @Test
    public void test3() {
        Map map = new HashMap();
        //添加
        map.put("AA", 123);
        map.put(45, 123);
        map.put("BB", 56);
        //修改
        map.put("AA", 87);

        System.out.println(map);

        Map map1 = new HashMap();
        map1.put(34, 344);
        map1.put("dsakd", 123);
        map1.putAll(map);

        System.out.println(map1);

        //移除
        Object value = map.remove("AA");
        System.out.println(value);
        System.out.println(map);

        map1.clear();
        System.out.println(map.size());//里面还是存在的
        System.out.println(map);
    }

    //元素查询的操作:
    @Test
    public void test4() {
        Map map = new HashMap();
        map.put(34, 344);
        map.put("dsakd", 123);

        System.out.println(map.get(34));


    }

    //元视图操作的方法:
    @Test
    public void test5() {
        Map map = new HashMap();
        map.put(34, 344);
        map.put("dsakd", 123);
        //将key转换为set来进行迭代器遍历key
        Set s1 = map.keySet();
        Iterator iterator=s1.iterator();
        while (iterator.hasNext()){
            System.out.println(iterator.next());
        }
        //将values编程Collection来遍历values
        Collection values=map.values();
        for (Object o :values){//加强for，写入需要遍历的东西，加上属性
            System.out.println(o);
        }

        Set set = map.entrySet();
        Iterator iterator1 = set.iterator();
        Object next = iterator1.next();
        //netryset中的元素都是entry
        Map.Entry entry= (Map.Entry)next;
            System.out.println(entry.getKey() + "------------->" + entry.getValue());

        //方式二:遍历
        Set keySet = map.keySet();
        Iterator iterator2 = keySet.iterator();
        while( iterator2.hasNext()){
            Object key = iterator2. next();
            Object value = map. get(key);
            System. out. println(key + "====="+value );
        }

    }
}
